﻿using System;
using System.Buffers;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using SuperSocket.ProtoBase;

namespace SuperSocket.Client.HttpCode;

internal sealed class HttpPipelineFilter : HttpHeaderPipelineFilterBase<HttpRequest>
{
    private const string ContentLength = "Content-Length";

    protected override IPipelineFilter<HttpRequest> GetNextPipelineFilter(HttpRequest request)
    {
        var strContentLength = request.Items.Get(ContentLength);

        if (!string.IsNullOrEmpty(strContentLength))
        {
            var contentLength = int.Parse(strContentLength);

            if (contentLength > 0)
                return new HttpBodyPipelineFilter(contentLength, request);
        }

        return new HttpChunkPipeLineFilter(request);
    }
}

internal class HttpPipelineFilter1 : IPipelineFilter<HttpRequest>
{
    private static readonly char _TAB = '\t';

    private static readonly char _COLON = ':';

    private static readonly ReadOnlyMemory<byte> HeaderTerminator = "\r\n\r\n"u8.ToArray();

    public IPackageDecoder<HttpRequest> Decoder { get; set; }

    public IPipelineFilter<HttpRequest> NextFilter { get; internal set; }

    private HttpRequest _currentRequest;

    private long _bodyLength;

    public HttpRequest Filter(ref SequenceReader<byte> reader)
    {
        if (_bodyLength == 0)
        {
            var terminatorSpan = HeaderTerminator.Span;

            if (!reader.TryReadTo(out ReadOnlySequence<byte> pack, terminatorSpan,
                    advancePastDelimiter: false)) //尝试读取到 _headerTerminator 的位置。然后返回
                return null;

            reader.Advance(terminatorSpan.Length);

            var request = ParseHttpHeaderItems(pack);

            var contentLength = request.Items?["content-length"];

            if (string.IsNullOrEmpty(contentLength)) // no content
                return request;

            var bodyLength = long.Parse(contentLength);

            if (bodyLength == 0)
                return request;

            _bodyLength = bodyLength;
            _currentRequest = request;

            return Filter(ref reader);
        }

        if (reader.Remaining < _bodyLength)
            return null;

        var body = reader.Sequence.Slice(reader.Consumed, _bodyLength);

        _currentRequest.Body = body.CopySequence();

        reader.Advance(_bodyLength);

        return _currentRequest;
    }

    private HttpRequest ParseHttpHeaderItems(ReadOnlySequence<byte> header)
    {
        var headerText = header.GetString(Encoding.UTF8);
        var reader = new StringReader(headerText);
        var firstLine = reader.ReadLine();

        if (string.IsNullOrEmpty(firstLine))
            return null;

        var items = new NameValueCollection();

        var prevKey = string.Empty;
        var line = string.Empty;

        while (!string.IsNullOrEmpty(line = reader.ReadLine()))
        {
            if (line.StartsWith(_TAB) && !string.IsNullOrEmpty(prevKey))
            {
                var currentValue = items.Get(prevKey);
                items[prevKey] = currentValue + line.Trim();
                continue;
            }

            int pos = line.IndexOf(_COLON);

            if (pos <= 0)
                continue;

            string key = line.Substring(0, pos);

            if (!string.IsNullOrEmpty(key))
                key = key.Trim();

            if (string.IsNullOrEmpty(key))
                continue;

            var valueOffset = pos + 1;

            if (line.Length <= valueOffset) //No value in this line
                continue;

            var value = line.Substring(valueOffset);

            if (!string.IsNullOrEmpty(value) && value.StartsWith(' ') && value.Length > 1)
                value = value.Substring(1);

            var existingValue = items.Get(key);

            if (string.IsNullOrEmpty(existingValue))
            {
                items.Add(key, value);
            }
            else
            {
                items[key] = existingValue + ", " + value;
            }

            prevKey = key;
        }

        var metaInfo = firstLine.Split(' ');

        if (metaInfo.Length != 3)
        {
            // invalid first line
            return null;
        }

        return new HttpRequest(metaInfo[0], metaInfo[1], metaInfo[2], items);
    }

    public void Reset()
    {
        _bodyLength = 0;
        _currentRequest = null;
    }

    public object Context { get; set; }
}

internal class HttpChunkDataPipelineFilter : FixedSizePipelineFilter<HttpRequest>
{
    readonly HttpRequest _currentRequest;

    public HttpChunkDataPipelineFilter(int size, HttpRequest request)
        : base(size)
    {
        _currentRequest = request;
    }

    protected override HttpRequest DecodePackage(ref ReadOnlySequence<byte> buffer)
    {
        _currentRequest.Body = buffer.CopySequence();

        return _currentRequest;
    }
}